package com.ruoyi.light.service.impl;

import com.aliyun.dingtalktodo_1_0.models.CreateTodoTaskResponseBody;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.ChainWrappers;
import com.ruoyi.common.aliyun.DingdingApi;
import com.ruoyi.common.async.AsyncManager;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.domain.dict.DictDevice;
import com.ruoyi.common.domain.dict.view.DictDeviceView;
import com.ruoyi.common.domain.light.LitConfigErr;
import com.ruoyi.common.domain.light.LitErr;
import com.ruoyi.common.domain.light.LitErrLog;
import com.ruoyi.common.domain.light.view.LitErrView;
import com.ruoyi.common.enums.LightErrStatusEnum;
import com.ruoyi.common.enums.LightStatusEnum;
import com.ruoyi.common.mybatisplus.QueryWrTool;
import com.ruoyi.common.utils.LocalDateTimeUtil;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.dict.mapper.DictDeviceViewMapper;
import com.ruoyi.dict.service.IDictDeviceService;
import com.ruoyi.light.mapper.LitErrMapper;
import com.ruoyi.light.mapper.LitErrViewMapper;
import com.ruoyi.light.service.ILitConfigErrRoleService;
import com.ruoyi.light.service.ILitConfigErrService;
import com.ruoyi.light.service.ILitErrLogService;
import com.ruoyi.light.service.ILitErrService;
import com.ruoyi.system.service.ISysUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 安灯异常处理记录 服务层实现
 *
 * @author ruoyi
 * @date 2022-02-24
 */
@Service
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class LitErrServiceImpl extends ServiceImpl<LitErrMapper, LitErr> implements ILitErrService {

    private final IDictDeviceService dictDeviceService;
    private final DictDeviceViewMapper dictDeviceViewMapper;
    private final LitErrViewMapper litErrViewMapper;
    private final ILitConfigErrService litConfigErrService;
    private final ILitErrLogService litErrLogService;
    private final ILitConfigErrRoleService litConfigErrRoleService;
    private final RedisCache redisCache;
    private final ISysUserService userService;
    public static final Long INIT_ROLE_ID = 2L;
    public static final Long CHECK_ROLE_ID = 3L;


    private String getSerialNumber() {
        return redisCache.getSerialNumber("LitErr", "E");
    }




    @Override
    public List<LitErrView> getLitErrViewMyErrPage(Long deviceId, String status) {
        LambdaQueryChainWrapper<LitErrView> queryChain = ChainWrappers.lambdaQueryChain(litErrViewMapper).eq(LitErr::getDeviceId, deviceId);
        if (StringUtils.isBlank(status)) {
            LocalDate startDate = LocalDate.now();
            LocalDate endDate = LocalDate.now().plusDays(1);
            queryChain.between(LitErr::getUpdateTime, startDate, endDate);
        } else {
            if (status.contains(","))
                queryChain.in(LitErr::getStatus, Convert.toStrList(status));
            else
                queryChain.eq(LitErr::getStatus, status);

        }
        List<LitErrView> list = queryChain.list();
        return list;
    }


    @Override
    public Page<LitErrView> getLitErrViewPage(Page<LitErrView> page, LitErrView litErr) {
        QueryWrapper<LitErrView> litErrQueryWrapper = QueryWrTool.queryWrapper(litErr);

        if (litErr.getErrId() != null) {
            LitConfigErr configErr = litConfigErrService.getById(litErr.getErrId());
            switch (configErr.getErrLv()) {
                case 1 -> litErrQueryWrapper.eq("err_id_lv1", litErr.getErrId());
                case 2 -> litErrQueryWrapper.eq("err_id_lv2", litErr.getErrId());
            }
        }
        Page<LitErrView> litErrPage = litErrViewMapper.selectPage(page, litErrQueryWrapper);
        return litErrPage;
    }

    @Override
    public Page<LitErrView> getLitErrViewMyErrPage(Page<LitErrView> page, LitErrView litErr) {
        QueryWrapper<LitErrView> litErrQueryWrapper = QueryWrTool.queryWrapper(litErr);

        if (litErr.getErrId() != null) {
            LitConfigErr configErr = litConfigErrService.getById(litErr.getErrId());
            switch (configErr.getErrLv()) {
                case 1 -> litErrQueryWrapper.eq("err_id_lv1", litErr.getErrId());
                case 2 -> litErrQueryWrapper.eq("err_id_lv2", litErr.getErrId());
            }
        }
        List<Long> roleIdList = SecurityUtils.getRoleIds();
        String username = SecurityUtils.getUsername();
        List<Long> allErrIds = litConfigErrRoleService.getAllErrIdsRoleIds(roleIdList);
        litErrQueryWrapper.and(allErrIds.size() > 0, t->t.in("err_id", allErrIds)
                .or().eq("init_by", username))
                .ne("status", LightErrStatusEnum.ok)
                .orderByDesc("id");
        Page<LitErrView> litErrPage = litErrViewMapper.selectPage(page, litErrQueryWrapper);
        return litErrPage;
    }

    @Transactional
    public AjaxResult oper(LitErr litErrParam, String operType) {
        LitErr litErr = litErrParam.getId() == null ? litErrParam : this.getById(litErrParam.getId());
        LoginUser loginUser = SecurityUtils.getLoginUser();
        boolean perm = loginUser.getUserId() == 1;
        if (!perm) {
            List<Long> roleIdList = SecurityUtils.getRoleIds();
            switch (operType) {
                case "init":
                    perm = roleIdList.contains(INIT_ROLE_ID);
                    break;
                case "sign":
                case "lift":
                    perm = litConfigErrRoleService.exists(litErr.getErrId(), roleIdList);
                    break;
                case "ok":
                case "un_lift":
                    perm = roleIdList.contains(CHECK_ROLE_ID);
                    break;
                default:
                    return AjaxResult.error("操作不存在");
            }
        }
        if (!perm) {
            return AjaxResult.error("权限不足");
        }
        switch (operType) {
            case "init":
                return init(litErr);
            case "sign":
                return sign(litErrParam, litErr);
            case "lift":
                return lift(litErrParam, litErr);
            case "ok":
                return ok(litErrParam, litErr);
            case "un_lift":
                return unLift(litErrParam, litErr);
        }
        return AjaxResult.error("操作不存在");
    }





    @Transactional
    public AjaxResult init(LitErr litErr) {
        DictDeviceView dictDevice = dictDeviceViewMapper.selectById(litErr.getDeviceId());
        if (dictDevice == null) {
            return AjaxResult.error("设备不存在");
        }
        if (dictDevice.getLitStatus() != null && !LightStatusEnum.green.equals(dictDevice.getLitStatus())) {
            return AjaxResult.error("该设备已发起安灯警报, 无法重复发起");
        }

        litErr.setErrNo(getSerialNumber());
        LitConfigErr configErr = litConfigErrService.getById(litErr.getErrId());
        if (configErr.getErrLv() == 1) {
            litErr.setErrIdLv1(configErr.getErrId());
        } else {
            litErr.setErrIdLv1(configErr.getParentId());
            litErr.setErrIdLv2(configErr.getErrId());
        }
        String username = SecurityUtils.getUsername();
        LocalDateTime now = LocalDateTime.now();
        litErr.setInitBy(username);
        litErr.setUpdateBy(username);
        litErr.setInitTime(now);
        litErr.setUpdateTime(now);
        litErr.setStatus(LightErrStatusEnum.init);
        litErr.setLitStatus(LightStatusEnum.red);
        this.save(litErr);
        dictDevice.setLitStatus(LightStatusEnum.red);
        dictDevice.setLitStatusTime(now);
        dictDeviceService.updateById(dictDevice);
        LitErrLog litErrLog = new LitErrLog(litErr.getErrNo(), litErr.getErrId(), litErr.getLitStatus(),
                litErr.getStatus(), now, username, litErr.getRemark(), 0L);
        litErrLogService.save(litErrLog);

        AsyncManager.me().execute(() -> {
            List<String> list = getDingdingUnionIdByErrId(litErr.getErrId());
            if (list.size() > 0) {
                createDingDingTask(list, litErr, dictDevice, configErr);
            }
        });
        return AjaxResult.success();
    }

    private void createDingDingTask(List<String> list, LitErr litErr, DictDeviceView dictDevice, LitConfigErr configErr) {
        String subject = MessageUtils.message("dingding.task.subject",
                dictDevice.getDeviceName(), configErr.getErrName());
        String desc = MessageUtils.message("dingding.task.desc",
                dictDevice.getDeviceName(), dictDevice.getDeviceGroupName(),
                configErr.getErrName(), litErr.getRemark(),
                litErr.getUpdateBy(), LocalDateTimeUtil.parseStr(litErr.getInitTime()));


            CreateTodoTaskResponseBody task = DingdingApi.createTask(subject, desc, list);
            LitErr litErr1 = new LitErr();
            litErr1.setId(litErr.getId());
            litErr1.setDingdingTaskId(task.getId());
            litErr1.setDingdingTaskStatus(0);
            this.updateById(litErr1);

    }

    private List<String> getDingdingUnionIdByErrId(Long errId) {
        List<Long> roleIds = litConfigErrRoleService.getAllRoleIdsErrId(errId);
        if (roleIds.size() == 0) {
            return new ArrayList<>();
        }
        List<SysUser> userList = userService.getUserListByRoleIds(roleIds);
        if (userList.size() == 0) {
            return new ArrayList<>();
        }
        return userList.stream().map(SysUser::getDingdingUnionid).filter(StringUtils::isNotBlank).collect(Collectors.toList());
    }


    @Transactional
    public AjaxResult sign(LitErr litErrParam, LitErr litErr) {

        if (!LightErrStatusEnum.init.equals(litErr.getStatus()) && !LightErrStatusEnum.un_lift.equals(litErr.getStatus())) {
            return AjaxResult.error("当前状态无法签到");
        }

        String username = SecurityUtils.getUsername();
        LocalDateTime now = LocalDateTime.now();
        litErr.setSignBy(username);
        litErr.setUpdateBy(username);
        Duration duration = Duration.between(litErr.getInitTime(), now);
        litErr.setSignCostTimes(duration.toSeconds());
        litErr.setSignTime(now);
        litErr.setUpdateTime(now);
        litErr.setLitStatus(LightStatusEnum.yellow);
        litErr.setStatus(LightErrStatusEnum.sign);
        this.updateById(litErr);
        //lit_err_log 先不写
        DictDevice dictDevice = new DictDevice();
        dictDevice.setDeviceId(litErr.getDeviceId());
        dictDevice.setLitStatus(LightStatusEnum.yellow);
        dictDevice.setLitStatusTime(now);
        dictDeviceService.updateById(dictDevice);
        LitErrLog litErrLog = new LitErrLog(litErr.getErrNo(), litErr.getErrId(), litErr.getLitStatus(),
                litErr.getStatus(), now, username, litErrParam.getRemark(), litErr.getSignCostTimes());

        litErrLogService.save(litErrLog);
        return AjaxResult.success();
    }

    @Transactional
    public AjaxResult lift(LitErr litErrParam, LitErr litErr) {
        if (!LightErrStatusEnum.sign.equals(litErr.getStatus())) {
            return AjaxResult.error("当前状态无法处理");
        }
        litErr.setRemark(litErrParam.getRemark());

        String username = SecurityUtils.getUsername();
        LocalDateTime now = LocalDateTime.now();
        litErr.setLiftBy(username);
        litErr.setUpdateBy(username);
        Duration duration = Duration.between(litErr.getSignTime(), now);
        litErr.setLiftCostTimes(duration.toSeconds());
        litErr.setLiftTime(now);
        litErr.setUpdateTime(now);
        litErr.setLitStatus(LightStatusEnum.blue);
        litErr.setStatus(LightErrStatusEnum.lift);
        this.updateById(litErr);
        //lit_err_log 先不写

        //lit_err_log 先不写
        DictDevice dictDevice = new DictDevice();
        dictDevice.setDeviceId(litErr.getDeviceId());
        dictDevice.setLitStatus(LightStatusEnum.blue);
        dictDevice.setLitStatusTime(now);
        dictDeviceService.updateById(dictDevice);
        LitErrLog litErrLog = new LitErrLog(litErr.getErrNo(), litErr.getErrId(), litErr.getLitStatus(),
                litErr.getStatus(), now, username, litErrParam.getRemark(), litErr.getLiftCostTimes());

        litErrLogService.save(litErrLog);


        AsyncManager.me().execute(() -> DingdingApi.overTask(litErr.getDingdingTaskId()));

        return AjaxResult.success();
    }

    @Transactional
    public AjaxResult ok(LitErr litErrParam, LitErr litErr) {
        if (!LightErrStatusEnum.lift.equals(litErr.getStatus())) {
            return AjaxResult.error("当前状态无法复线");
        }

        litErr.setRemark(litErrParam.getRemark());

        String username = SecurityUtils.getUsername();
        LocalDateTime now = LocalDateTime.now();
        litErr.setUpdateBy(username);
        Duration duration = Duration.between(litErr.getSignTime(), now);
        litErr.setErrCostTimes(duration.toSeconds());
        litErr.setUpdateTime(now);
        litErr.setStatus(LightErrStatusEnum.ok);
        litErr.setLitStatus(LightStatusEnum.green);
        this.updateById(litErr);

        DictDevice dictDevice = new DictDevice();
        dictDevice.setDeviceId(litErr.getDeviceId());
        dictDevice.setLitStatus(LightStatusEnum.green);
        dictDevice.setLitStatusTime(now);
        dictDeviceService.updateById(dictDevice);

        Duration duration2 = Duration.between(litErr.getLiftTime(), now);

        LitErrLog litErrLog = new LitErrLog(litErr.getErrNo(), litErr.getErrId(), litErr.getLitStatus(),
                litErr.getStatus(), now, username, litErrParam.getRemark(), duration2.toSeconds());

        litErrLogService.save(litErrLog);

        return AjaxResult.success();

    }

    @Transactional
    public AjaxResult unLift(LitErr litErrParam, LitErr litErr) {
        if (!LightErrStatusEnum.lift.equals(litErr.getStatus())) {
            return AjaxResult.error("当前状态无法操作");
        }
        litErr.setRemark(litErrParam.getRemark());
        litErr.setErrId(litErrParam.getErrId());
        LitConfigErr configErr = litConfigErrService.getById(litErr.getErrId());
        if (configErr.getErrLv() == 1) {
            litErr.setErrIdLv1(configErr.getErrId());
        } else {
            litErr.setErrIdLv1(configErr.getParentId());
            litErr.setErrIdLv2(configErr.getErrId());
        }
        String username = SecurityUtils.getUsername();
        LocalDateTime now = LocalDateTime.now();
        litErr.setUpdateBy(username);
        litErr.setUpdateTime(now);
        litErr.setStatus(LightErrStatusEnum.un_lift);
        litErr.setLitStatus(LightStatusEnum.red);
        this.updateById(litErr);


        DictDevice dictDevice = new DictDevice();
        dictDevice.setDeviceId(litErr.getDeviceId());
        dictDevice.setLitStatus(LightStatusEnum.red);
        dictDevice.setLitStatusTime(now);
        dictDeviceService.updateById(dictDevice);

        Duration duration2 = Duration.between(litErr.getLiftTime(), now);
        LitErrLog litErrLog = new LitErrLog(litErr.getErrNo(), litErr.getErrId(), litErr.getLitStatus(),
                litErr.getStatus(), now, username, litErrParam.getRemark(), duration2.toSeconds());

        litErrLogService.save(litErrLog);

        AsyncManager.me().execute(() -> {
            List<String> list = getDingdingUnionIdByErrId(litErr.getErrId());
            if (list.size() > 0) {
                DictDeviceView dictDeviceView = dictDeviceViewMapper.selectById(litErr.getDeviceId());
                createDingDingTask(list, litErr, dictDeviceView, configErr);
            }
        });
        return AjaxResult.success();
    }

}